package com.tender.utils;

import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * @author cuisudong
 * <p>
 * 使用java 8的 LocalDateTime
 */
public class TimeUtils {

    public static final String SHORT_DEFAULT_FORMAT = "yyyy-MM-dd";
    public static final String SHORT_FORMAT_1 = "yyyy-MM-dd";
    public static final String SHORT_FORMAT_2 = "yyyy/MM/dd";
    public static final String SHORT_FORMAT_3 = "yyyyMMdd";
    public static final String SHORT_FORMAT_4 = "yyyy-MM";

    public static final String LONG_DEFAULT_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String LONG_FORMAT_1 = "yyyy-MM-dd HH";
    public static final String LONG_FORMAT_2 = "yyyy-MM-dd HH:mm";

    public static LocalDateTime now() {
        return LocalDateTime.now();
    }

    public static int year(LocalDateTime localDateTime) {
        return localDateTime.get(ChronoField.YEAR);
    }

    public static int month(LocalDateTime localDateTime) {
        return localDateTime.get(ChronoField.MONTH_OF_YEAR);
    }

    public static int day(LocalDateTime localDateTime) {
        return localDateTime.get(ChronoField.DAY_OF_MONTH);
    }

    public static int dayOfWeek(LocalDateTime localDateTime) {
        return localDateTime.get(ChronoField.DAY_OF_WEEK);
    }

    public static int hourOfDay(LocalDateTime localDateTime) {
        return localDateTime.get(ChronoField.HOUR_OF_DAY);
    }

    public static String format(LocalDateTime localDateTime) {
        return format(localDateTime, LONG_DEFAULT_FORMAT);
    }

    public static String format(LocalDateTime localDateTime, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(formatter);
    }

    public static String formatShort(LocalDate localDate) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(SHORT_FORMAT_1);
        return localDate.format(formatter);
    }

    public static String formatShort(LocalDate localDate, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return localDate.format(formatter);
    }

    /**
     * 非ISO-8601 的日期格式
     *
     * @param dateStr eg: 2021-04-08 12:30:11
     *                or 2021-04-08 12:30
     *                or 2021-04-08 12
     */
    public static LocalDateTime parse(String dateStr) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(LONG_DEFAULT_FORMAT);
        return LocalDateTime.parse(dateStr, formatter);
    }

    /**
     * 非 ISO-8601 的日期格式
     *
     * @param dateStr eg: 2021-04-08 12:30:11
     *                or 2021-04-08 12:30
     *                or 2021-04-08 12
     */
    public static LocalDateTime parse(String dateStr, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return LocalDateTime.parse(dateStr, formatter);
    }

    /**
     * ISO-8601 format  只能用这个来 解析时间字符串
     * eg: 2021-04-08
     * or: 20210408
     * or: 2021/04/08
     *
     * @param dateStr
     * @return
     */
    public static LocalDate parseShort(String dateStr) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(SHORT_FORMAT_1);
        return LocalDate.parse(dateStr, formatter);
    }

    public static LocalDate parseShort(String dateStr, String format) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
        return LocalDate.parse(dateStr, formatter);
    }

    public static LocalDateTime addMonth(LocalDateTime localDateTime, int interval) {
        return localDateTime.plusMonths(interval);
    }

    public static int daysBetween(LocalDateTime start, LocalDateTime end) {
        Duration duration = Duration.between(start, end);
        return (int) duration.toDays();
    }

    public static LocalDateTime date2LocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDateTime();
    }

    public static LocalDate date2LocalDate(Date date) {
        LocalDateTime localDateTime = date2LocalDateTime(date);
        return localDateTime2LocalDate(localDateTime, SHORT_DEFAULT_FORMAT);
    }

    public static LocalDate date2LocalDate(Date date, String format) {
        LocalDateTime localDateTime = date2LocalDateTime(date);
        return localDateTime2LocalDate(localDateTime, format);
    }

    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        return Date.from(zonedDateTime.toInstant());
    }

    public static Date parseShort2Date(String date) {
        return parseShort2Date(date, SHORT_FORMAT_1);
    }

    public static Date parseShort2Date(String date, String format) {
        if (StringUtils.isBlank(date)) {
            return null;
        }
        return TimeUtils.localDateTime2Date(localDate2LocalDateTime(parseShort(date, format)));
    }

    public static Date parse2Date(String dateTime) {
        return parse2Date(dateTime, LONG_DEFAULT_FORMAT);
    }

    public static Date parse2Date(String dateTime, String format) {
        if (StringUtils.isBlank(dateTime)) {
            return null;
        }
        return TimeUtils.localDateTime2Date(parse(dateTime, format));
    }

    public static LocalDateTime localDate2LocalDateTime(LocalDate localDate) {
        return localDate.atStartOfDay();
    }

    /**
     *
     * @param localDateTime {@link TimeUtils#SHORT_FORMAT_2}
     * @param localDateTime {@link TimeUtils#SHORT_FORMAT_3}
     * @param localDateTime {@link TimeUtils#SHORT_FORMAT_1}
     * @param localDateTime {@link TimeUtils#SHORT_DEFAULT_FORMAT}
     * @param format format 格式化字符模板
     * @return
     */
    public static LocalDate localDateTime2LocalDate(LocalDateTime localDateTime, String format) {
        return parseShort(format(localDateTime, format), format);
    }

    /**
     * @param localDateTimeStr eg： "2022-04-12 12:11:11"
     * @return
     */
    public static LocalDate localDateTime2LocalDate(String localDateTimeStr, String format) {
        LocalDateTime parse = parse(localDateTimeStr);
        return localDateTime2LocalDate(parse, format);
    }

    public static boolean compare(LocalDateTime end, LocalDateTime start) {
        return end.compareTo(start) >= 0;
    }

    public static LocalDateTime getStartDate(Integer interval) {
        LocalDate now = LocalDate.now();
        LocalDate localDate = now.plusMonths(interval);
        LocalDate firstDay = LocalDate.of(localDate.getYear(), localDate.getMonthValue(), 1);
        return parse(formatShort(firstDay, SHORT_FORMAT_1) + " 00:00:00", LONG_DEFAULT_FORMAT);
    }

    public static LocalDateTime getEndDate(int interval) {
        LocalDate now = LocalDate.now();
        LocalDate plusMonths = now.plusMonths(interval);
        LocalDate lastDayOfMonth = plusMonths.with(TemporalAdjusters.lastDayOfMonth());
        return parse(formatShort(lastDayOfMonth, SHORT_FORMAT_1) + " 23:59:59", LONG_DEFAULT_FORMAT);
    }

    public static boolean betweenTwoDate(LocalDateTime start, LocalDateTime end, LocalDateTime source) {
        return compare(source, start) && compare(end, source);
    }

    public static String getStartDayOkWeek() {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int value = dayOfWeek.getValue();
        return formatShort(now.minusDays(value - 1)) + " 00:00:00";
    }

    public static String getEndDayOfWeek() {
        LocalDate now = LocalDate.now();
        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int value = dayOfWeek.getValue();
        return formatShort(now.plusDays(7 - value)) + " 23:59:59";
    }

    public static String getFirstDay(LocalDate localDate, String format) {
        LocalDate firstDate = localDate.with(TemporalAdjusters.firstDayOfMonth());
        return formatShort(firstDate, format);
    }

    public static String getFirstDay(LocalDate localDate) {
        return getFirstDay(localDate, SHORT_FORMAT_1);
    }

    public static String getLastDay(LocalDate localDate, String format) {
        LocalDate lastDate = localDate.with(TemporalAdjusters.lastDayOfMonth());
        return formatShort(lastDate, format);
    }

    public static String getLastDay(LocalDate localDate) {
        return getLastDay(localDate, SHORT_FORMAT_1);
    }

//    public static void main(String[] args) {
//        // 当前时间
//        System.out.println(format(now()));
//        System.out.println(format(now(), SHORT_DEFAULT_FORMAT));
//        System.out.println(format(now(), SHORT_FORMAT_4));
//        // 当前年
//        System.out.println(year(now()));
//        // 当前月
//        System.out.println(month(now()));
//        // 当前日
//        System.out.println(day(now()));
//        // 当前星期几
//        System.out.println(dayOfWeek(now()));
//        // 当前日小时
//        System.out.println(hourOfDay(now()));
//        // 月份加
//        System.out.println(addMonth(now(), 1));
//        // 月份减
//        System.out.println(addMonth(now(), -1));
//        // 解析日期
//        System.out.println(parse("2021-11-09 12", LONG_FORMAT_1));
//        System.out.println(parse("2021-04-08 12:30", LONG_FORMAT_2));
//        System.out.println(parse("2021-04-08 12:30:11"));
//        // ISO-8601 format
//        System.out.println(parseShort("2021-04-08"));
//        System.out.println(parseShort("20210408", SHORT_FORMAT_3));
//        // 相差天数
//        System.out.println(daysBetween(now(), addMonth(now(), 1)));
//        // date -> localDateTime
//        System.out.println(date2LocalDateTime(new Date()));
//        // localDateTime -> date
//        System.out.println(localDateTime2Date(now()));
//        // localDate2LocalDateTime
//        System.out.println(localDate2LocalDateTime(LocalDate.now()));
//        System.out.println(LocalDate.now().atTime(0,0,1));
//        System.out.println(LocalDate.now().atTime(23,59,59));
//        // formatShort
//        System.out.println(formatShort(LocalDate.now()));
//        // formatShort 指定格式
//        System.out.println(formatShort(LocalDate.now(), SHORT_FORMAT_2));
//        // 获取当前时间对应的本月的第一天
//        // System.out.println(getStartDate());
//        // 获取当前时间对应的本月的最后天
//        System.out.println(getEndDate(0));
//        System.out.println(localDateTime2LocalDate(now(),TimeUtils.SHORT_DEFAULT_FORMAT));
//        System.out.println(localDateTime2LocalDate(now(),TimeUtils.SHORT_FORMAT_2));
//        System.out.println(localDateTime2LocalDate("2022-04-12 12:11:11", TimeUtils.SHORT_FORMAT_2));
//        System.out.println("----------");
//        System.out.println(date2LocalDate(new Date()));
//        System.out.println(formatShort(date2LocalDate(new Date()), TimeUtils.SHORT_FORMAT_2));
//        System.out.println("---------- 本周时间测试 ------");
//        System.out.println(getStartDayOkWeek());
//        System.out.println(getEndDayOfWeek());
//
//        System.out.println(getFirstDay(localDate));
//        System.out.println(getFirstDay(localDate, SHORT_FORMAT_3));
//
//        System.out.println(getLastDay(localDate));
//        System.out.println(getLastDay(localDate, SHORT_FORMAT_3));
//    }
//
//    public static void main(String[] args) {
//        String str = "2022-12-14";
//        Date date = parseShort2Date(str);
//        System.out.println(date);
//
//        str = str + " 12:34:22";
//        Date date1 = parse2Date(str);
//        System.out.println(date1);
//    }

}